package com.yfqy.admin.transform;

import cn.hutool.core.collection.CollUtil;
import com.yfqy.admin.domain.entity.Label;
import com.yfqy.admin.domain.mapper.LabelMapper;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
public class LabelNameTranslator {

    private final Map<Long, String> labelCache = new ConcurrentHashMap<>();

    private final LabelMapper labelMapper;

    public LabelNameTranslator(LabelMapper labelMapper) {
        this.labelMapper = labelMapper;
    }

    /**
     * 根据标签id转标签名称
     *
     * @param o
     */
    public void translationLabel(Object o) {
        if (o == null) {
            return;
        }
        try {
            if (o instanceof List<?> list) {
//                processBatchObject(list);
                for (Object item : list) {
                    processSingleObject(item);
                }
            } else {
                processSingleObject(o);
            }
        } catch (Exception e) {
            throw new RuntimeException("标签信息转换失败", e);
        }
    }


    private void processBatchObject(List<?> list) throws Exception {
        List<Long> labelIds = new ArrayList<>();
        for (Object item : list) {
            Class<?> clazz = item.getClass();
            Field labelIdField = getField(clazz, "labelId");
            if (labelIdField == null) {
                continue;
            }
            Field labelNameField = getField(clazz, "labelName");
            if (labelNameField == null) {
                continue;
            }
            labelIdField.setAccessible(true);
            Long labelId = (Long) labelIdField.get(item);
            labelIds.add(labelId);
        }
        if (CollUtil.isEmpty(labelIds)) {
            return;
        }
        List<Label> labels = labelMapper.selectByIds(labelIds);
        if (CollUtil.isEmpty(labels)) {
            labelIds.forEach(labelCache::remove);
            return;
        }
        // label id:name
        Map<Long, String> labelIdNameMap = labels.stream().collect(Collectors.toMap(Label::getId, Label::getLabelName));
        for (Object item : list) {
            Class<?> clazz = item.getClass();
            Field labelIdField = getField(clazz, "labelId");
            if (labelIdField == null) {
                continue;
            }
            Field labelNameField = getField(clazz, "labelName");
            if (labelNameField == null) {
                continue;
            }
            labelIdField.setAccessible(true);
            Long labelId = (Long) labelIdField.get(item);

            String labelName = labelIdNameMap.get(labelId);
            labelNameField.setAccessible(true);
            labelNameField.set(item, labelName);
            labelCache.put(labelId, labelName);
        }
    }

    private void processSingleObject(Object obj) throws Exception {
        if (obj == null) {
            return;
        }
        Class<?> clazz = obj.getClass();

        Field labelIdField = getField(clazz, "labelId");
        if (labelIdField == null) {
            return;
        }
        Field labelNameField = getField(clazz, "labelName");
        if (labelNameField == null) {
            return;
        }

        labelIdField.setAccessible(true);
        Long labelId = (Long) labelIdField.get(obj);
        if (labelId == null) {
            return;
        }
        //
        String labelName = labelCache.computeIfAbsent(labelId, labelMapper::getLabelNameById);
        labelNameField.setAccessible(true);
        labelNameField.set(obj, labelName);
    }

    private Field getField(Class<?> clazz, String fieldName) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            // 尝试从父类查找
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                return getField(superClass, fieldName);
            }
            return null;
        }
    }
}
